;; EX-16.scm - Trigger based sample playback instrument

;; A synth definition that will playback a memory resident signal when
;; triggered by a control rate signal.

(synthdef-send
 (synthdef
  "sample-playback"
  ((out 0) (bufnum 0) (rate 1) (trigger 0) (startPos 0) (loop 0)
   (pan 0.5) (gain 0.0))
  (Out.ar out (Pan2.ar (PlayBuf.ar 1 bufnum rate trigger startPos loop) 
		       pan gain))))

;; The buffer is allocated and the synth is created.

(begin 
  (define ~b (bID))
  (define ~s (nID))
  (-> "/b_allocRead" ~b (resolve "audio/metal.wav"))
  (-> "/s_new" "sample-playback" ~s 1 1 "bufnum" ~b))

;; If the trigger control is immediately reset to zero then the sound
;; is not triggered.  This is because both the set and the reset occur
;; within a single control period, and therefore the synth never sees
;; the unit value on the bus.  The time required before reset is a
;; function of the control period size.

(begin (-> "/n_set" ~s
	   "pan" (random -1 1)
	   "gain" (random 0.5 1.0)
	   "trigger" 1)
       (thread-sleep! 0.05)
       (-> "/n_set" ~s "trigger" 0))

;; A synth definition that writes a sawtooth wave to a control bus.

(synthdef-send
 (synthdef
  "sawtooth-controller"
  ((out 21) (freq 1))
  (Out.kr out (LFSaw.kr freq))))

;; Make an instance of the sawtooth-controller (C) and map the
;; sample-playback (S) to read the trigger value from C.

(begin 
  (define ~c (nID))
  (-> "/s_new" "sawtooth-controller" ~c 1 1 "out" 21)
  (-> "/n_map" ~s "trigger" 21))

;; Map controllers to set the frequency, playback rate, pan location
;; and gain controls.

(begin 
  (require (lib "rscC.ss"  "rscC")
	   (lib "rscCi.ss" "rscC"))
  (controller-initialize 4)
  (controller-interface 1 4))

(begin (ctl-setup! (c 0) "freq" (make-spec 1/4 24 'exponential) 2)
       (ctl-setup! (c 1) "rate" (make-spec 1/4 4 'lin))
       (ctl-setup! (c 2) "pan" (make-spec -1 1 'lin))
       (ctl-setup! (c 3) "gain" (make-spec 0.1 1 'exponential)))

(begin (-> "/n_map" ~c "freq" 0)
       (-> "/n_map" ~s "rate" 1 "pan" 2 "gain" 3))

;; Add lisp level oscillator to pan location.

(in-mthread 
 (let loop ((n 0))
   (ctl-value! (c 2) (sin n))
   (thread-sleep! 0.1)
   (loop (+ n 0.1))))

;; Cleanup

(begin (-> "/n_free" ~s ~c)
       (-> "/b_free" ~b)
       (bID-release ~b))
